<?php

namespace app\controller\admin\module\menu;

use app\controller\admin\module\AdminBaseController;
use app\controller\admin\module\menu\components\Position;
use think\exception\ValidateException;
use think\response\Json;
use think\response\View;

/**
 * 菜单
 * @auth-name 菜单列表
 * @auth-alias menu
 */
class Index extends AdminBaseController
{
    protected string $modelName = 'menu';

    /**
     * @auth-name 主页
     * @auth-alias index
     * @return View
     */
    public function index(): View
    {
        return fetch('/admin/menu/index');
    }

    /**
     * @auth-name 列表
     * @auth-alias list
     * @return Json
     */
    public function list(): Json
    {
        $arr = $this->getList();
        if(!empty($arr['rows'])){
            foreach($arr['rows'] as $k => $v) {
//                !empty($v['controller']) and $arr['rows'][$k]['location'] = '/admin/' . ($v['controller_alias'] ? : strtolower($v['controller'])) . (!empty($v['method']) ? '/' . ($v['method_alias'] ? : strtolower($v['method'])) : '');
                !empty($v['module']) and $arr['rows'][$k]['location'] = '/admin/' . $v['module'] . (!empty($v['method']) ? '/' . ($v['method_alias'] ? : strtolower($v['method'])) : '');
                $arr['rows'][$k]['serialNumber'] = $k + 1;
            }
        }
        return json($arr);
    }

    private function getList(): array
    {
//        $arr = $this->model->getPageList([], 'id, icon, name, controller, controller_alias, method, method_alias, request_method, pid, level, sort, is_home_page, show, status');
        $arr = $this->model->getPageList([], 'id, icon, name, module, method, method_alias, request_method, pid, level, sort, is_home_page, show, status');
        array_multisort(array_column($arr['rows'], 'is_home_page'), SORT_DESC, array_column($arr['rows'], 'level'), SORT_ASC,  array_column($arr['rows'], 'sort'), SORT_DESC, $arr['rows']);
        $arr['rows'] = infiniteCategory($arr['rows'], 0, 0);
        if(!empty($arr) and $arr['rows'][0]['id'] === 1 and $arr['rows'][0]['pid'] === 0){
            unset($arr['rows'][0]);
            $arr['rows'] = array_values($arr['rows']);
        }
        return $arr;
    }

    /**
     * @auth-name 添加页面
     * @auth-alias add
     * @return View
     */
    public function add(): View
    {
        return fetch('/admin/menu/add', [
            'menuList' => $this->menuList()
        ]);
    }

    /**
     * @auth-name 添加提交
     * @auth-alias add
     * @auth-request-method post
     * @return Json
     */
    public function addPost(): Json
    {
        $pid = values('post.pid', 0);    //上级菜单ID
        $name = values('post.name');   //当前菜单名
        $module = values('post.module');   //模块名
//        $controller = values('post.controller');   //控制器
        $method = values('post.method');   //方法
//        $controllerAlias = values('post.controller_alias', $controller ? strtolower($controller) : '');   //控制器别名
        $methodAlias = values('post.method_alias', $method ? strtolower($method) : '');   //方法别名
        $requestMethod = values('post.request_method', 1);   //请求方式
        $sort = values('post.sort', 0);  //排序
        $icon = values('post.icon');  //图标
        $show = values('post.show', 0);    //是否显示
        $status = values('post.status', 0);    //是否开启
        try {
            $this->model->startTrans();
            $this->validate([
                'pid' => $pid,
                'name' => $name,
                'sort' => $sort,
            ],[
                'pid|上级菜单' => ['require'],
                'name|菜单名' => ['require'],
                'sort|排序' => ['require'],
            ]);
            $parentInfo = $pid > 0 ? $this->model->getInfo(['id' => $pid], 'id, lef, righ, level') : $this->model->getInfo(['id' => 1], 'id, lef, righ, level');
            if(empty($parentInfo)){
                throw new ValidateException('未找到菜单信息');
            }
            $data = [
                'lef' => $parentInfo['righ'],
                'righ' => ($parentInfo['righ'] + 1),
                'pid' => $pid,
                'icon' => $icon,
                'name' => $name,
                'module' => $module,
//                'controller' => $controller,
                'method' => $method,
//                'controller_alias' => $controllerAlias,
                'method_alias' => $methodAlias,
                'request_method' => $requestMethod,
                'level' => ($parentInfo['level'] + 1),
                'sort' => $sort,
                'show' => $show,
                'status' => $status,
                'addtime' => time(),
            ];
            if(!$this->model->add($data)){
                throw new ValidateException('新增失败');
            }

            $incResult = $this->model->getInfo([['lef', '>', $parentInfo['righ']]], 'id') ? Position::getInstance()->inc($parentInfo) : [];
            if (!empty($incResult) and $incResult['code'] != 200) {
                throw new ValidateException($incResult['msg']);
            }
            $this->resetRouteCache();
            putAdminLog("新增菜单[" . json_encode($data) . "]");
            $this->model->commit();
            return responseMsg('新增成功', 200);
        }catch (ValidateException $e){
            $this->model->rollback();
            return responseMsg($e->getError());
        }catch (\Exception $e){
            $this->model->rollback();
            return responseMsg($e->getMessage());
        }
    }

    /**
     * @auth-name 编辑页面
     * @auth-alias edit
     * @return View
     */
    public function edit(): View
    {
        $id = values('get.id', 0);
        empty($id) and missPage();
        $info = $this->model->getInfo(['id' => $id], 'id, pid, icon, name, module, method, method_alias, request_method, show, status, sort');
//        $info = $this->model->getInfo(['id' => $id], 'id, pid, icon, name, controller, controller_alias, method, method_alias, request_method, show, status, sort');
        empty($info) and errorData();
        return fetch('/admin/menu/edit', [
            'info' => $info,
            'menuList' => $this->menuList()
        ]);
    }

    /**
     * @auth-name 编辑提交
     * @auth-alias edit
     * @auth-request-method post
     * @return Json
     */
    public function editPost(): Json
    {
        $id = values('post.id', 0);    //上级菜单ID
        if(empty($id)){
            return responseMsg('缺少必要参数，请重新进入编辑页面');
        }
        $info = $this->model->getInfo(['id' => $id], 'id, pid, lef, righ');
        if(empty($info)){
            return responseMsg('未找到菜单信息');
        }
        $pid = values('post.pid', 0);    //上级菜单ID
        $name = values('post.name');   //当前菜单名
        $module = values('post.module');   //模块名
//        $controller = values('post.controller');   //控制器
        $method = values('post.method');   //方法
//        $controllerAlias = values('post.controller_alias', $controller ? strtolower($controller) : '');   //控制器别名
        $methodAlias = values('post.method_alias', $method ? strtolower($method) : '');   //方法别名
        $requestMethod = values('post.request_method', 1);   //请求方式
        $sort = values('post.sort', 0);  //排序
        $icon = values('post.icon');  //图标
        $show = values('post.show', 0);    //是否显示
        $status = values('post.status', 0);    //是否开启
        try {
            $this->model->startTrans();
            $this->validate([
                'pid' => $pid,
                'name' => $name,
                'sort' => $sort,
            ],[
                'pid|上级菜单' => ['require'],
                'name|菜单名' => ['require'],
                'sort|排序' => ['require'],
            ]);
            $newParentInfo = $pid > 0 ? $this->model->getInfo(['id' => $pid], 'id, lef, righ, level') : $this->model->getInfo(['id' => 1], 'id, lef, righ, level');
            if(empty($newParentInfo)){
                throw new ValidateException('未找到菜单信息');
            }
            //只有编辑改变了此菜单的父级才要调整位置
            $delResult = ($info['pid'] != $pid and !empty($this->model->getInfo([['lef', '>', $info['righ']]], 'id'))) ? Position::getInstance()->dec($info) : [];
            if (!empty($delResult) and $delResult['code'] != 200) {
                throw new ValidateException($delResult['msg']);
            }
            //位置都调整完了之后，将此菜单位置更新
            if(!$this->model->edit(['id' => $id], [
                'pid' => $pid,
                'icon' => $icon,
                'name' => $name,
                'lef' => $newParentInfo['righ'],
                'righ' => ($newParentInfo['righ'] + 1),
                'module' => $module,
//                'controller' => $controller,
                'method' => $method,
//                'controller_alias' => $controllerAlias,
                'method_alias' => $methodAlias,
                'request_method' => $requestMethod,
                'level' => ($newParentInfo['level'] + 1),
                'sort' => $sort,
                'show' => $show,
                'status' => $status,
            ])){
                throw new ValidateException('编辑失败');
            }
            $incResult = $this->model->getInfo([['lef', '>', $newParentInfo['righ']]], 'id') ? ($info['pid'] != $pid ? Position::getInstance()->inc($newParentInfo) : []) : [];
            if (!empty($incResult) and $incResult['code'] != 200) {
                throw new ValidateException($incResult['msg']);
            }
            putAdminLog("编辑菜单[$id]");
            $this->resetRouteCache();
            $this->model->commit();
            return responseMsg('编辑成功', 200);
        }catch (ValidateException $e){
            $this->model->rollback();
            return responseMsg($e->getError());
        }catch (\Exception $e){
            $this->model->rollback();
            return responseMsg($e->getMessage());
        }

    }

    /**
     * @auth-name 删除
     * @auth-alias del
     * @auth-request-method delete
     * @return Json
     */
    public function del(): Json
    {
        $id = values('id', 0);
        if(empty($id)){
            return responseMsg('缺少必要参数，请重新进入列表页面');
        }
        $info = $this->model->getInfo(['id' => $id], 'id, pid, lef, righ, level');
        if(empty($info)){
            return responseMsg('未找到菜单信息');
        }
        try {
            $this->model->startTrans();

            if(!$this->model->del([
                ['lef', '>=', $info['lef']],
                ['righ', '<=', $info['righ']]
            ])){
                throw new ValidateException('删除失败');
            }
            $decResult = $this->model->getInfo([['lef', '>', $info['righ']]], 'id') ? Position::getInstance()->dec($info, (($info['righ'] - $info['lef']) > 1 ? ($info['righ'] - $info['level']) : 2)) : [];
            if(!empty($decResult) and $decResult['code'] != 200){
                throw new ValidateException($decResult['msg']);
            }
            putAdminLog("删除菜单[" . json_encode($info) . "]");
            $this->resetRouteCache();
            $this->model->commit();
            return responseMsg('删除成功', 200);
        }catch (\Exception $e){
            $this->model->rollback();
            return responseMsg('删除失败');
        }
    }

    /**
     * @auth-name 状态修改
     * @auth-alias state
     * @auth-request-method post
     * @return Json
     */
    public function state(): Json
    {
        $idx = values('idx', []);
        $status = values('status', 1);
        if(!empty($idx)){
            $res = $this->model->edit(['id' => $idx], ['status' => $status]);
            if($res){
                putAdminLog("修改菜单信息[" . json_encode($idx) . "]");
                $this->resetRouteCache();
                return responseMsg('操作成功', 200);
            }
        }
        return responseMsg('操作失败，请稍后重试');
    }

    /**
     * 菜单列表
     * @return array
     */
    private function menuList(): array
    {
        $arr = $this->model->getList(['is_home_page' => 0, 'level' => [0,1]], 'id, name, pid, level, sort, status');
        array_multisort( array_column($arr, 'level'), SORT_ASC,  array_column($arr, 'sort'), SORT_DESC, $arr);
        $menuList = infiniteCategory($arr);
        foreach($menuList as $k => $v){
            $menuList[$k]['name'] = str_repeat('&nbsp;&nbsp;&nbsp;&nbsp;', $v['level'] - 1) . '|---' . $v['name'];
        }
        return $menuList;
    }

    /**
     * 加载某个类的所有公共方法 入 菜单内
     * @return json
     */
    public function reloadSecondaryMethod(): Json
    {
        $id = values('id', 0);
        if(empty($id)){
            return responseMsg('缺少必要参数，请重新进入列表页面');
        }
        $res = components\SecondaryMethod::getInstance()->reload($id);  //TODO 如果要恢复到之前的方式，将方法里的Position->reload注释
        if(!empty($res) and $res['code'] == 200){
            $this->resetRouteCache();
            return responseMsg('操作成功', 200);
        }
        return responseMsg($res['msg'], $res['code']);
    }

    /**
     * 重置路由缓存
     * @return void
     */
    private function resetRouteCache(){
        delCaches('RouteMenuList');
    }

}